// Study Swift EveryWhere
// duoba
// 2016.03.10


import UIKit

var str = "Hello, playground"

/* *********/
/* 常量和变量 */
/* *********/

let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 1
var x = 0.0, y = 0.1, z = 0.2
var welcomeMessage: String
let 🐶🐮 = "dogcow"
let π = 3.14159
let 你好 = "你好世界"
print (🐶🐮)
// 有一种情况下必须要用分号，即你打算在同一行内写多条独立的语句
let cat = "🐱"; print(cat)
// 整数范围
let minValue = UInt8.min
let maxValue = UInt8.max
let minV = Int64.max
let maxV = Int64.min
// 数值型字面量，一个二进制数，前缀是0b，一个八进制数，前缀是0o，一个十六进制数，前缀是0x
let decimalInteger = 17
let binaryInteger = 0b10001
let octalInteger = 0o21
let hexadecimalInteger = 0x11
// 整数和浮点数转换必须显式指定类型，pi 等于 3.14159，所以被推测为 Double 类型
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// 类型别名
typealias MyInt = UInt16
let maxMyInt = Int16.max
// 布尔值
let orangesAreOrange = true
let turnipsAreDelicious = false
// 元组（tuples）把多个值组合成一个复合值。元组内的值可以是任意类型，并不要求是相同类型
let http404Error = (404, "Not Found")
print (http404Error.0)
// 元组内容分解
let (statusCode, statusMessage) = http404Error
print (statusCode)
print (statusMessage)
// 如果你只需要一部分元组值，分解的时候可以把要忽略的部分用下划线（ _ ）标记
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// 可选类型，使用可选类型（optionals）来处理值可能缺失的情况。可选类型表示：有值，等于 x 或者没有值
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// 打印变量类型？？？
convertedNumber.debugDescription
_stdlib_getDemangledTypeName(convertedNumber)
// 可选值的if语句以及强制解析， 你可以使用if语句来判断一个可选是否包含值。如果可选类型有值，结果是true；如果没有值，结果是false。
// 当你确定可选类型确实包含值之后，你可以在可选的名字后面加一个感叹号（!）来获取值。这个惊叹号表示 我知道这个可选有值，请使用它。
if convertedNumber != nil {
    print (convertedNumber)
}
if let actualNumber = convertedNumber {
    // 注意看类型，现在已经不是Optional了，就是Int了
    print (actualNumber)
    _stdlib_getDemangledTypeName(actualNumber)
}
// nil, nil不能用于非可选的常量和变量。
var serverResponseCode: Int? = 404
serverResponseCode = nil
var surveyAnswer: String?
// 隐式解析可选类型, String? -> String!
let possibleString: String? = "An optional string."
print (possibleString)
let assumedString: String! = "An implicitly unwrapped optional string."
_stdlib_getDemangledTypeName(assumedString) // 注意看类型, 和下面的definiteString是不一样的
if let definiteString = assumedString {
    print (definiteString)
    _stdlib_getDemangledTypeName(definiteString)
}
// 断言
let myAge = 18
assert(myAge > 0, "A person's age cannot be less than 18:)")
// 何时使用断言
// 当条件可能为假时使用断言，但是最终一定要保证条件为真，这样你的代码才能继续运行。断言的适用情景：
// 整数类型的下标索引被传入一个自定义下标脚本实现，但是下标索引值可能太小或者太大。
// 需要给函数传入一个值，但是非法的值可能导致函数不能正常执行。
// 一个可选值现在是nil，但是后面的代码运行需要一个非nil值。

/* *********/
/* 基本运算符 */
/* *********/

// 术语
// 一元运算符(操作单一元素)： 如 -a !b c++
// 二元运算符(操作两个对象)： 2+3
// 三元运算符(操作三个对象)： a ? b : c

// 赋值运算符
let abcd = 10
var xyz = 5
xyz = abcd
// 算术运算符
// + - * /
let dogC: String = "d"
let catC: String = "c"
let dogCat = dogC + catC
// 求余运算符
9 % 4
-9 % 4
8 % 2.5
// 自增和自减运算
// 当++前置的时候，先自増再返回。
// 当++后置的时候，先返回再自增。
var a = 0
let b = ++a  // a 和 b 现在都是 1
let c = a++  // a 现在 2, 但 c 是 a 自增前的值 1”
// 比较运算符
1 == 1   // true
2 != 1   // true
2 > 1    // true
1 < 2    // true
1 >= 1   // true
2 <= 1   // false
// 三目运算符
// 原型是 问题? 答案1 : 答案2  根据问题成立与否作出二选一的操作，如果成立，返回答案1，如果不成立，返回答案2
// 三目运算符是以下代码的缩写形式
let contentHeight = 40
let hasHeader = true
var rowHeight = contentHeight
if hasHeader {
    rowHeight = rowHeight + 50
}
else {
    rowHeight = rowHeight + 20
}
// 空合运算符
// 空合运算符(a ?? b)将对可选类型a进行空判断，如果a包含一个值就进行解封，否则就返回一个默认值b.
// 这个运算符有两个条件: 
// 1. 表达式a必须是Optional类型
// 2. 默认值b的类型必须要和a存储值的类型保持一致
// 空合并运算符是对以下代码的简短表达方法
// a != nil ? a! : b
let defaultColorName = "red"
var userDefinedColorName:String?   //默认值为nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// 区间运算符
// 闭区间运算符 a...b 包含a和b以及中间的所有值
for index in 1...3 {
    let indexNumber = index
}
// 半开区间运算符 a..<b 包含a，但不包含b
for index in 2..<6 {
    let indexNumber = index
}
// 逻辑运算
// 逻辑与 a||b
// 逻辑与 a&&b
// 逻辑非  !a

// 使用括号来明确优先级
var enteredDoorCode = true
var passedRetinaScan = true
var hasDoorKey = false
var knowsOverridePassword = true
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
    print("Welcome!")
} else {
    print("ACCESS DENIED")
}

/* ************/
/* 字符串和字符 */
/* ************/

// 初始化空字符串
var emptyString = ""
var anotherEmptyString = String()
// 字符串可变性
var variableString = "Horse"
variableString += " and carriage"
// 字符串是值类型
// 使用字符
for character in "Dog!🐱".characters {
    print(character)
}
// 计算字符数量
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
print("unusualMenagerie has \(unusualMenagerie.characters.count) characters")
// 连接字符串和字符
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
var instruction = "look over"
instruction += string2
let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// 比较字符串 - 如果两个字符串以同一顺序包含完全相同的字符
let quotation = "we are the same"
let sameQuotation = "we are the same"
if quotation == sameQuotation {
    print("SAME!")
}
// Unicode 标量
let dogString = "Dog!🐶"
for scalar in dogString.unicodeScalars {
    print("\(scalar.value)")
}

/* *********/
/* 集合类型 */
/* *********/

// 集合 - 集合用来储存相同类型并且没有确定顺序的值
var letters = Set<Character>()
letters.insert("a")
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
var anotherFavoriteGenres: Set = ["Classical", "Rock", "Hip hop"]
var setCount = anotherFavoriteGenres.count
anotherFavoriteGenres.remove("Rock")
for genre in favoriteGenres {
    let xGenre = genre
}
// 集合操作: union - 联合  intersect - 交集   subtract - 不在该合集中   exclusiveOr - 交集之外
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
oddDigits.union(evenDigits).sort()
oddDigits.intersect(evenDigits).sort()
oddDigits.subtract(singleDigitPrimeNumbers).sort()
oddDigits.exclusiveOr(singleDigitPrimeNumbers).sort()
// 集合比较:
// isSubsetOf - 判断一个集合中的值是否也被包含在另外一个集合中
// isSupersetOf - 判断一个集合中包含的值是另一个集合中所有的值
// isDisjointWith - 判断两个结合是否不含有相同的值
let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]
houseAnimals.isSubsetOf(farmAnimals)
farmAnimals.isSupersetOf(houseAnimals)
farmAnimals.isDisjointWith(cityAnimals)
// 字典 - 字典是一种存储多个相同类型的值的容器。每个值（value）都关联唯一的键（key），键作为字典中的这个值数据的标识符
var namesOfIntegers = Dictionary<Int, String>()
namesOfIntegers[12] = "HoHo"
var airports: [String:String] = ["TYO": "Tokyo", "DUB": "Dublin"]
var anotherAirports = ["Beijing": "ShouDu", "Shanghai": "PuDong"]
airports["LHR"] = "London"
// 字典遍历
for (airportCode, airportName) in airports {
    print ("\(airportCode): \(airportName)")
}
for airportCode in anotherAirports.keys {
    print ("Airport code: \(airportCode)")
}
for airportName in anotherAirports.values {
    print ("Airport name: \(airportName)")
}
// 数组 - 数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中
var someInts = [Int]()
someInts.append(3)
someInts = []
var threeDouble = [Double](count: 3, repeatedValue: 0.0)
var anotherThreeDouble = Array(count: 3, repeatedValue: 2.5)
var shoppingList: [String] = ["cake", "egg", "milk"]
shoppingList = ["Milk", "Cake", "Eggs"]
shoppingList.append("Flour")
shoppingList += ["Baking Powder"]
var firstItem = shoppingList[0]
shoppingList.insert("Maple", atIndex: 3)
// 数组的遍历
for item in shoppingList {
    print (item)
}
for (index, value) in shoppingList.enumerate() {
    print ("Item \(index + 1): \(value)")
}

/* *********/
/* 控制流 */
/* *********/

// For-In
for index in 1...5 {
}
let base = 3
let power = 10
var answer = 1
// 如果你不需要知道区间内每一项的值，你可以使用下划线（ _ ）替代变量名来忽略对值的访问
for _ in 1...power {
    answer *= base
}
// 遍历字典
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
    print("\(animalName)s have \(legCount) legs")
}
// For 条件递增
for var i = 0; i < 3; i++ {
    let xI = i
}
// While循环： while和repeat-while
// while
var square = 0
var diceRoll = 0
let finalSquare = 25
var board = [Int](count: finalSquare + 1, repeatedValue: 0)
while square < finalSquare {
    if ++diceRoll == 7 {
        diceRoll = 1
    }
    square += diceRoll
    if square < board.count {
        square += board[square]
    }
}
print("Game over!")
// repeat-while
board = [Int](count: finalSquare + 1, repeatedValue: 0)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
square = 0
repeat {
    square += board[square]
    if ++diceRoll == 7 { diceRoll = 1 }
    square += diceRoll
} while square < finalSquare
print("Game over!")
// 条件语句： if 和 switch
// switch语句必须是完备的。这就是说，每一个可能的值都必须至少有一个 case 分支与之对应。
// 在某些不可能涵盖所有值的情况下，你可以使用默认（default）分支满足该要求，这个默认分支必须在switch语句的最后面
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
    print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
    print("\(someCharacter) is a consonant")
default:
    print("\(someCharacter) is not a vowel or a consonant")
}
// 区间匹配
let count = 3_000_000_000_000
let countedThings = "stars in the Milky Way"
var naturalCount: String
switch count {
case 0:
    naturalCount = "no"
case 1...3:
    naturalCount = "a few"
case 4...9:
    naturalCount = "several"
case 10...99:
    naturalCount = "tens of"
case 100...999:
    naturalCount = "hundreds of"
case 1000...999_999:
    naturalCount = "thousands of"
default:
    naturalCount = "millions and millions of"
}
print("There are \(naturalCount) \(countedThings).")
// 元组区间
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    print("(0, 0) is at the origin")
case (_, 0):
    print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
    print("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
    print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// 控制转移语句: Continue & Break
// Continue: 语句告诉一个循环体立刻停止本次循环迭代，重新开始下次循环迭代。就好像在说“本次循环迭代我已经执行完了”，但是并不会离开整个循环体。
// Break: 语句会立刻结束整个控制流的执行。当你想要更早的结束一个switch代码块或者一个循环体时，你都可以使用break语句。

// 带标签的语句
/*
gameLoop: while square != finalSquare {
    if ++diceRoll == 1 { diceRoll = 1 }
    switch square + diceRoll {
    case finalSquare:
        break gameLoop
    case let newSquare where newSquare > finalSquare:
        continue gameLoop
    default:
        square += diceRoll
        square += board[square]
    }
}
print("Game over!")
*/


/* *********/
/* 函数 */
/* *********/

// 函数的定义与调用
func sayHello(personName: String) -> String {
    return "Hello " + personName
}
func sayHelloWorld() -> String {
    return "Hello, World!"
}
func sayHello(personName: String, alreadyGreeted: Bool) -> String {
    if (alreadyGreeted) {
        return "Bye!"
    }
    else {
        return "Hello"
    }
}
func sayGoodBye(personName: String) {
    print ("Bye!")
}
// 返回多个函数值
func minMax(array: [Int], nothing: Bool) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if (value < currentMin) {
            currentMin = value
        }
        else if value > currentMax {
            currentMax = value
        }
        
    }
    return (currentMin, currentMax)
}
// 返回多个可选函数值
func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if (array.isEmpty) {
        return nil
    }
    else {
        var currentMin = array[0]
        var currentMax = array[0]
        for value in array[1..<array.count] {
            if (value < currentMin) {
                currentMin = value
            }
            else if value > currentMax {
                currentMax = value
            }
            
        }
        return (currentMin, currentMax)
    }
}
let nilValue = minMax([])
// 默认参数值
func someFunction(parameterWithDefault: Int = 2) -> Int{
    return parameterWithDefault * 10
}
someFunction()
someFunction(10)
// 可变参数 - 一个函数最多只能有一个可变参数
func arithmeticMean(numbers: [Double]) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total
}
arithmeticMean([1.2, 2.4, 23.4, 54.3, 23.0])
// 输入输出参数
func swapTwoInts(inout a: Int, inout b: Int) {
    let tempA = a
    a = b
    b = tempA
}
var someInt = 3
var anotherSomeInt = 666
swapTwoInts(&someInt, b: &anotherSomeInt)
print (someInt)
print (anotherSomeInt)

/* *********/
/* 闭包 */
/* *********/

// 闭包是自包含的函数代码块，可以在代码中被传递和使用
// 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这就是所谓的闭合并包裹着这些常量和变量，俗称闭包

// sort方法
let names = ["Teddy", "Candy", "DuoDuo"]

func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sort(backwards)
// 闭包表达式
//{ (parameters) -> returnType in
//    statements
//}
reversed = names.sort({ (s1: String, s2: String) -> Bool in
    return s1 > s2
})
reversed = names.sort( { s1, s2 in return s1 > s2 } )
reversed = names.sort( { s1, s2 in s1 > s2} )
reversed = names.sort( { $0 > $1 } )
reversed = names.sort(<)
reversed = names.sort(>)
// 返回函数
func makeIncrementor(forIncrement amout: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amout
        return runningTotal
    }
    return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
incrementByTen()
incrementByTen()
incrementByTen()
let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven()
incrementByTen()

/* *********/
/* 枚举 */
/* *********/


/* *********/
/* 类和结构体 */
/* *********/

struct Resolution {
    var width = 0
    var height = 0
}
class VideoMode {
    var resolution = Resolution()
    var interlaced = false
    var frameRate = 0.0
    var name: String?
}
let someResolution = Resolution()
let someVideoMode = VideoMode()
print (someResolution.height)
print (someVideoMode.resolution.height)
let vga = Resolution(width: 640, height: 480)
// 结构体和枚举是值类型
enum CompassPoint {
    case North, South, East, West
}
var currentDirection = CompassPoint.West
let rememberedDirection = currentDirection
currentDirection = .East
if rememberedDirection == .West {
    print("The remembered direction is still .West")
}
// 类是引用类型
let hd = Resolution(width: 1920, height: 1280)
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
print (tenEighty.frameRate)

/* *********/
/* 继承 */
/* *********/

// 定义一个基类
class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }
    func makeNoise() {}
}
// 生成子类
class Bicycle: Vehicle {
    var hasBasket = false
}
let bicycle = Bicycle()
bicycle.hasBasket = true
bicycle.currentSpeed = 15.0
print (bicycle.description)
class Tandem: Bicycle {
    var currentNumberOfPassenagers = 0
}
let tandem = Tandem()
tandem.hasBasket = true
tandem.currentNumberOfPassenagers = 2
tandem.currentSpeed = 22.0
print (tandem.description)
// 重写
class Train: Vehicle {
    override func makeNoise() {
        print ("Choo Choo")
    }
}
// 重写属性
let train = Train()
train.makeNoise()
class Car: Vehicle {
    var gear = 1
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}
let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print (car.description)
class AutomaticCar: Car {
    override var currentSpeed: Double {
        didSet{
            gear = Int(currentSpeed / 10.0) + 1
        }
    }
}
let autoCar = AutomaticCar()
autoCar.currentSpeed = 120
print (autoCar.description)
// 防止重写 - final关键字

/* *********/
/* 构造过程 */
/* *********/

struct Fahrenheit {
    var temperature: Double
    init() {
        temperature = 21.0
    }
}
var f = Fahrenheit()
print ("The default temperature is \(f.temperature)")
struct Celsius {
    var temperatureInCelsius: Double
    init (fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init (fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
    init (_ celsius: Double) {
        temperatureInCelsius = celsius
    }
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
print (boilingPointOfWater.temperatureInCelsius)
print (freezingPointOfWater.temperatureInCelsius)
let bodyTemperature = Celsius(36)
print (bodyTemperature.temperatureInCelsius)
class SurveyQuestion {
    var text: String
    var response: String?
    init (text: String) {
        self.text = text
    }
    func ask() {
        print (text)
    }
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
cheeseQuestion.ask()
cheeseQuestion.response = "Yes!"
cheeseQuestion.response = nil


/* *********/
/* 错误处理 */
/* *********/

enum VendingMachineError: ErrorType {
    // 选择无效
    case InvalidSelection
     // 金额不足
    case InsufficientFunds(coinsNeeded: Int)
    // 缺货
    case OutOfStock
}
struct Item {
    var price: Int
    var count: Int
}
class VendingMachine {
    var inventory = [
        "Candy Bar": Item(price: 12, count: 7),
        "Chips": Item(price: 10, count: 4),
        "Pretzels": Item(price: 7, count: 11)
    ]
    var coinsDeposited = 0
    func dispenseSnack(snack: String) {
        print("Dispensing \(snack)")
    }
    func vend(itemNamed name: String) throws {
        guard let item = inventory[name] else {
            throw VendingMachineError.InvalidSelection
        }
        guard item.count > 0 else {
            throw VendingMachineError.OutOfStock
        }
        guard item.price <= coinsDeposited else {
            throw VendingMachineError.InsufficientFunds(coinsNeeded: item.price - coinsDeposited)
        }
    }
}

let favoriteSnacks = [
    "Alice": "Chips",
    "Bob": "Licorice",
    "Eve": "Pretzels"
]
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
    let snackName = favoriteSnacks[person] ?? "CandyBar"
    try vendingMachine.vend(itemNamed: snackName)
}
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
    try buyFavoriteSnack("Alice", vendingMachine: vendingMachine)
} catch VendingMachineError.InvalidSelection {
    print("Invalid Selection.")
} catch VendingMachineError.OutOfStock {
    print("Out of Stock.")
} catch VendingMachineError.InsufficientFunds(let coinsNeeded) {
    print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
}

/* *********/
/* 类型转换 */
/* *********/

// 类型转换在 Swift 中使用 is 和 as 操作符实现。这两个操作符提供了一种简单达意的方式去检查值的类型或者转换它的类型

class MediaItem {
    var name: String
    init(name:String) {
        self.name = name
    }
}
class Movie: MediaItem{
    var director: String
    init(name: String, director: String) {
        self.director = director
        super.init(name: name)
    }
}
class Song: MediaItem {
    var artist: String
    init(name: String, artist: String) {
        self.artist = artist
        super.init(name: name)
    }
}
let library = [
    Movie(name: "Casablanca", director: "Michael Curtiz"),
    Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
    Movie(name: "Citizen Kane", director: "Orson Welles"),
    Song(name: "The One And Only", artist: "Chesney Hawkes"),
    Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
var movieCount = 0
var songCount = 0
for item in library {
    if item is Movie {
        ++movieCount
    } else if item is Song {
        ++songCount
    }
}
print("Media library contains \(movieCount) movies and \(songCount) songs")
// 当你不确定向下转型可以成功时，用类型转换的条件形式(as?)。条件形式的类型转换总是返回一个可选值（optional value），并且若下转是不可能的，可选值将是 nil。这使你能够检查向下转型是否成功。
// 只有你可以确定向下转型一定会成功时，才使用强制形式(as!)。当你试图向下转型为一个不正确的类型时，强制形式的类型转换会触发一个运行时错误
for item in library {
    if let movie = item as? Movie {
        print("Movie: '\(movie.name)', dir. \(movie.director)")
    } else if let song = item as? Song {
        print("Song: '\(song.name)', by \(song.artist)")
    }
}

// AnyObject和Any的类型转换
// Swift为不确定类型提供了两种特殊类型别名：
// 1. AnyObject可以代表任何class类型的实例
// 2. Any可以表示任何类型，包括方法类型（function types)

let someObjects: [AnyObject] = [
    Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
    Movie(name: "Moon", director: "Duncan Jones"),
    Movie(name: "Alien", director: "Ridley Scott")
]
for object in someObjects {
    let movie = object as! Movie
    print("Movie: '\(movie.name)', dir. \(movie.director)")
}
for movie in someObjects as! [Movie] {
    print("Movie: '\(movie.name)', dir. \(movie.director)")
}

var things = [Any]()
things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" })

for thing in things {
    switch thing {
    case 0 as Int:
        print("zero as an Int")
    case 0 as Double:
        print("zero as a Double")
    case let someInt as Int:
        print("an integer value of \(someInt)")
    case let someDouble as Double where someDouble > 0:
        print("a positive double value of \(someDouble)")
    case is Double:
        print("some other double value that I don't want to print")
    case let someString as String:
        print("a string value of \"\(someString)\"")
    case let (x, y) as (Double, Double):
        print("an (x, y) point at \(x), \(y)")
    case let movie as Movie:
        print("a movie called '\(movie.name)', dir. \(movie.director)")
    case let stringConverter as String -> String:
        print(stringConverter("Michael"))
    default:
        print("something else")
    }
}

/* *********/
/* 嵌套类型 */
/* *********/

struct BlackjackCard {
    // 嵌套定义枚举型Suit
    enum Suit: Character {
        case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣"
    }
    // 嵌套定义枚举型Rank
    enum Rank: Int {
        case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten
        case Jack, Queen, King, Ace
        struct Values {
            let first: Int, second: Int?
        }
        var values: Values {
            switch self {
            case .Ace:
                return Values(first: 1, second: 11)
            case .Jack, .Queen, .King:
                return Values(first: 10, second: nil)
            default:
                return Values(first: self.rawValue, second: nil)
            }
        }
    }
    // BlackjackCard 的属性和方法
    let rank: Rank, suit: Suit
    var description: String {
        var output = "suit is \(suit.rawValue),"
        output += " value is \(rank.values.first)"
        if let second = rank.values.second {
            output += " or \(second)"
        }
        return output
    }
}
let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
print("theAceOfSpades: \(theAceOfSpades.description)")
let heartSymbol = BlackjackCard.Suit.Hearts.rawValue

/* *********/
/* 扩展 */
/* *********/

// 扩展就是向一个已有的类、结构体、枚举类型或者协议类型添加新功能（functionality）。这包括在没有权限获取原始源代码的情况下扩展类型的能力（即逆向建模）
// extension SomeType {
//     加到SomeType的新功能写在这里
// }

extension Double {
    var km: Double {
        return self * 1_000.0
    }
    var m: Double {
        return self
    }
    var cm: Double { return self / 100.0 }
    var mm: Double { return self / 1_000.0 }
    var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
let threeFeet = 3.0.ft

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
}

extension Rect {
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
    size: Size(width: 3.0, height: 3.0))

extension Int {
    func reprtitions(task:() -> ()) {
        for _ in 0..<self {
            task()
        }
    }
}

3.reprtitions({print("Hello!")})

extension Int {
    enum Kind {
        case Negative, Zero, Positive
    }
    var kind: Kind {
        switch self {
        case 0:
            return .Zero
        case let x where x > 0:
            return .Positive
        default:
            return .Negative
        }
    }
}
func printIntegerKinds(numbers: [Int]) {
    for number in numbers {
        switch number.kind {
        case .Negative:
            print("- ", terminator: "")
        case .Zero:
            print("0 ", terminator: "")
        case .Positive:
            print("+ ", terminator: "")
        }
    }
    print("")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])

/* *********/
/* 协议 */
/* *********/

// 对属性的规定
protocol FullyNamed {
    var fullName: String{ get }
}
struct Person: FullyNamed{
    var fullName: String
}
let john = Person(fullName: "John Appleseed")
class Starship: FullyNamed {
    var prefix: String?
    var name: String
    init(name: String, prefix: String? = nil) {
        self.name = name
        self.prefix = prefix
    }
    var fullName: String {
        return (prefix != nil ? prefix! + " " : "") + name
    }
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// 对方法的规定
protocol RandomNumberGenerator {
    func random() -> Double
}
class LinearCongruentialGenerator: RandomNumberGenerator {
    var lastRandom = 42.0
    let m = 139968.0
    let a = 3877.0
    let c = 29573.0
    func random() -> Double {
        lastRandom = ((lastRandom * a + c) % m)
        return lastRandom / m
    }
}
let generator = LinearCongruentialGenerator()
print("Here's a random number: \(generator.random())")
print("And another one: \(generator.random())")

// 对构造器的规定
protocol SomeProtocol {
    init(someParameter: Int)
}
class SomeClass: SomeProtocol {
    required init(someParameter: Int) {
    
    }
}
class Dice {
    let sides: Int
    let generator: RandomNumberGenerator
    init(sides: Int, generator: RandomNumberGenerator) {
        self.sides = sides
        self.generator = generator
    }
    func roll() -> Int {
        return Int(generator.random() * Double(sides)) + 1
    }
}
var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
for _ in 1...5 {
    print ("Random dice roll is \(d6.roll())")
}

/* *********/
/* 泛型 */
/* *********/

func swapTwoValues<T>(inout a: T, inout _ b: T) {
    let tempA = a
    a = b
    b = tempA
}

struct Stack<T> {
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    }
    mutating func pop() -> T {
        return items.removeLast()
    }
}
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")

let fromTheTop = stackOfStrings.pop()
extension Stack {
    var topItem: T? {
        return items.isEmpty ? nil : items[items.count - 1]
    }
}
if let topItem = stackOfStrings.topItem {
    print("The top item on the stack is \(topItem).")
}

/* *********/
/* 访问控制 */
/* *********/

// 显式的public类
public class SomePublicClass {
    // 显式的public类成员
    public var somePublicProperty = 0
    // 隐式的internal类成员
    var someInternalProperty = 0
    // 显式的private类成员
    private func somePrivateMethod() {}
}
// 隐式的internal类
class SomeInternalClass {
    // 隐式的internal类成员
    var someInternalProperty = 0
    // 显式的private类成员
    private func somePrivateMethod() {}
}
// 显式的private类
private class SomePrivateClass {
    // 隐式的private类成员
    var somePrivateProperty = 0
    // 隐式的private类成员
    func somePrivateMethod() {}
}


















